<template>
  <div class="table-of-contents" :class="{ 'is-sticky': isSticky, 'is-collapsed': isCollapsed }">
    <div class="toc-header">
      <h2 class="toc-title">目录</h2>
      <button class="toggle-button" @click="toggleCollapse" :title="isCollapsed ? '展开目录' : '收起目录'">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <polyline v-if="isCollapsed" points="6 9 12 15 18 9"></polyline>
          <polyline v-else points="18 15 12 9 6 15"></polyline>
        </svg>
      </button>
    </div>

    <nav class="toc-nav" v-show="!isCollapsed">
      <ul v-if="tocItems.length > 0" class="toc-list">
        <li
          v-for="(item, index) in tocItems"
          :key="index"
          class="toc-item"
          :class="{
            'is-active': activeId === item.id,
            [`level-${item.level}`]: true
          }"
        >
          <a
            :href="`#${item.id}`"
            class="toc-link"
            @click.prevent="scrollToHeading(item.id)"
          >
            {{ item.text }}
          </a>
        </li>
      </ul>
      <div v-else class="toc-empty">
        没有找到标题
      </div>
    </nav>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';

const props = defineProps({
  contentSelector: {
    type: String,
    default: '.post-content'
  },
  headingSelector: {
    type: String,
    default: 'h1, h2, h3, h4'
  },
  offset: {
    type: Number,
    default: 100
  }
});

// 提取的目录项
const tocItems = ref([]);
// 当前活动的标题ID
const activeId = ref('');
// 是否处于固定位置
const isSticky = ref(false);
// 是否折叠目录
const isCollapsed = ref(false);
// 是否为移动端
const isMobile = ref(window.innerWidth < 768);

// 在移动设备上默认折叠
onMounted(() => {
  if (isMobile.value) {
    isCollapsed.value = true;
  }

  // 监听窗口大小变化
  window.addEventListener('resize', () => {
    isMobile.value = window.innerWidth < 768;
    if (isMobile.value) {
      isCollapsed.value = true;
    }
  });
});

// 切换折叠状态
const toggleCollapse = () => {
  isCollapsed.value = !isCollapsed.value;
};

// 解析文章内容并提取标题
const parseContent = () => {
  const contentElement = document.querySelector(props.contentSelector);
  if (!contentElement) return;

  const headings = Array.from(contentElement.querySelectorAll(props.headingSelector));

  // 为没有id的标题生成id
  headings.forEach((heading, index) => {
    if (!heading.id) {
      heading.id = `heading-${index}`;
    }
  });

  // 提取标题信息
  tocItems.value = headings.map(heading => {
    // 获取标题级别
    const level = parseInt(heading.tagName.substring(1));

    return {
      id: heading.id,
      text: heading.textContent,
      level
    };
  });
};

// 滚动到指定标题
const scrollToHeading = (id) => {
  const element = document.getElementById(id);
  if (!element) return;

  const top = element.getBoundingClientRect().top + window.pageYOffset - props.offset;

  window.scrollTo({
    top,
    behavior: 'smooth'
  });
};

// 监听滚动，更新活动标题
const handleScroll = () => {
  // 检查是否应该固定目录
  const scrollY = window.scrollY;
  isSticky.value = scrollY > 300;

  // 找出当前可见的标题
  const headingElements = tocItems.value.map(item => document.getElementById(item.id));

  // 排除不存在的元素
  const validHeadings = headingElements.filter(el => el !== null);

  if (validHeadings.length === 0) return;

  // 找出当前在视口中或刚刚离开视口顶部的标题
  for (let i = 0; i < validHeadings.length; i++) {
    const heading = validHeadings[i];
    const rect = heading.getBoundingClientRect();

    // 标题顶部在视口中，且距离顶部不超过offset
    if (rect.top <= props.offset + 50) {
      activeId.value = heading.id;
    } else {
      // 如果第一个标题还没到视口，就不设置activeId
      if (i === 0 && rect.top > props.offset + 50) {
        activeId.value = '';
      }
      break;
    }
  }
};

// 挂载和卸载事件监听
onMounted(() => {
  parseContent();
  window.addEventListener('scroll', handleScroll);
  // 初始检查一次
  handleScroll();
});

onUnmounted(() => {
  window.removeEventListener('scroll', handleScroll);
});

// 监听内容变化并重新解析
watch(() => props.contentSelector, parseContent);
</script>

<style scoped>
.table-of-contents {
  width: 100%;
  max-width: 280px;
  background-color: var(--color-card);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  padding: 1rem;
  margin-bottom: 1.5rem;
  transition: all 0.3s ease;
  max-height: calc(100vh - 100px);
  overflow-y: auto;
  position: sticky;
  top: 80px;
}

.toc-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--color-border);
}

.toc-title {
  font-size: 1.1rem;
  margin: 0;
  font-weight: 600;
  color: var(--color-text);
}

.toggle-button {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text-light);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  border-radius: 4px;
  transition: background-color 0.2s;
}

.toggle-button:hover {
  background-color: var(--color-hover);
}

.toc-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.toc-item {
  margin-bottom: 0.5rem;
  transition: all 0.2s;
}

.toc-link {
  display: block;
  text-decoration: none;
  color: var(--color-text-light);
  padding: 0.25rem 0;
  font-size: 0.9rem;
  transition: color 0.2s;
  border-left: 2px solid transparent;
  padding-left: 0.5rem;
}

.toc-link:hover {
  color: var(--color-primary);
}

.toc-item.is-active .toc-link {
  color: var(--color-primary);
  border-left-color: var(--color-primary);
  font-weight: 500;
}

/* 缩进不同级别的标题 */
.toc-item.level-2 {
  padding-left: 0;
}

.toc-item.level-3 {
  padding-left: 1rem;
}

.toc-item.level-4 {
  padding-left: 2rem;
}

.toc-empty {
  color: var(--color-text-light);
  font-style: italic;
  font-size: 0.9rem;
}

/* 是否固定在视口 */
.table-of-contents.is-sticky {
  position: sticky;
  top: 100px;
}

/* 折叠状态 */
.table-of-contents.is-collapsed {
  max-height: auto;
}

.toc-nav {
  overflow: hidden;
  transition: max-height 0.3s ease;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .table-of-contents {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    top: auto;
    max-width: 100%;
    margin: 0;
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    max-height: 50vh;
    z-index: 100;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
    padding: 0.5rem 1rem; /* Adjust padding to reduce unnecessary space */
  }

  .table-of-contents.is-collapsed {
    max-height: 48px; /* Keep the header visible */
    overflow: hidden;
  }

  .toc-header {
    margin-bottom: 0;
    position: sticky;
    top: 0;
    background: var(--color-card);
    z-index: 1;
    padding: 0.5rem 0; /* Adjust padding to ensure "目录" is fully visible */
  }

  .toc-title {
    font-size: 1rem; /* Adjust font size for better visibility */
    line-height: 1.2; /* Ensure proper line height */
  }

  .toc-nav {
    max-height: calc(50vh - 48px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch; /* Enhance scrolling on mobile */
  }

  /* 添加安全区域适配 */
  @supports (padding-bottom: env(safe-area-inset-bottom)) {
    .table-of-contents {
      padding-bottom: calc(0.5rem + env(safe-area-inset-bottom));
    }
  }

  /* 优化触摸区域 */
  .toc-link {
    padding: 0.5rem;
    margin: 0.25rem 0;
  }

  .toggle-button {
    padding: 0.5rem;
  }
}

/* 深色模式适配 */
@media (prefers-color-scheme: dark) {
  .table-of-contents {
    background-color: var(--color-card);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.2);
  }
}

/* 暗黑模式适配 */
.dark-theme .table-of-contents {
  background-color: var(--color-card);
  border-color: var(--color-border);
}
</style>
